/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.web.error;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

/**
 * 控制 {@code ErrorAttributes} 内容的选项。
 *
 * @author Scott Frederick
 * @author Phillip Webb
 * @since 2.3.0
 */
public final class ErrorAttributeOptions {

	private final Set<Include> includes;

	private ErrorAttributeOptions(Set<Include> includes) {
		this.includes = includes;
	}

	/**
	 * 判断错误响应中是否包含指定的错误属性选项。
	 * @param include 要判断的错误属性
	 * @return 如果错误响应中包含该 {@code Include} 属性，则返回 {@code true}，否则返回 {@code false}
	 */
	public boolean isIncluded(Include include) {
		return this.includes.contains(include);
	}

	/**
	 * 获取所有包含在错误响应中的属性选项。
	 * @return 包含的属性选项集合
	 */
	public Set<Include> getIncludes() {
		return this.includes;
	}

	/**
	 * 返回一个包含指定属性 {@link Include} 选项的 {@code ErrorAttributeOptions}。
	 * @param includes 要包含的错误属性
	 * @return 一个新的 {@code ErrorAttributeOptions} 实例
	 */
	public ErrorAttributeOptions including(Include... includes) {
		EnumSet<Include> updated = copyIncludes();
		updated.addAll(Arrays.asList(includes));
		return new ErrorAttributeOptions(Collections.unmodifiableSet(updated));
	}

	/**
	 * 返回一个排除指定属性 {@link Include} 选项的 {@code ErrorAttributeOptions}。
	 * @param excludes 要排除的错误属性
	 * @return 一个新的 {@code ErrorAttributeOptions} 实例
	 */
	public ErrorAttributeOptions excluding(Include... excludes) {
		EnumSet<Include> updated = copyIncludes();
		updated.removeAll(Arrays.asList(excludes));
		return new ErrorAttributeOptions(Collections.unmodifiableSet(updated));
	}

	private EnumSet<Include> copyIncludes() {
		return (this.includes.isEmpty()) ? EnumSet.noneOf(Include.class) : EnumSet.copyOf(this.includes);
	}

	/**
	 * 创建一个默认的 {@code ErrorAttributeOptions} 实例。
	 * @return 默认的 {@code ErrorAttributeOptions}
	 */
	public static ErrorAttributeOptions defaults() {
		return of();
	}

	/**
	 * 创建一个包含指定属性 {@link Include} 选项的 {@code ErrorAttributeOptions} 实例。
	 * @param includes 要包含的错误属性
	 * @return 一个新的 {@code ErrorAttributeOptions} 实例
	 */
	public static ErrorAttributeOptions of(Include... includes) {
		return of(Arrays.asList(includes));
	}

	/**
	 * 创建一个包含指定属性 {@link Include} 选项的 {@code ErrorAttributeOptions} 实例。
	 * @param includes 要包含的错误属性
	 * @return 一个 {@code ErrorAttributeOptions} 实例
	 */
	public static ErrorAttributeOptions of(Collection<Include> includes) {
		return new ErrorAttributeOptions(
				(includes.isEmpty()) ? Collections.emptySet() : Collections.unmodifiableSet(EnumSet.copyOf(includes)));
	}

	/**
	 * 可包含在错误响应中的错误属性枚举。
	 */
	public enum Include {

		/**
		 * 包含异常类名属性。
		 */
		EXCEPTION,

		/**
		 * 包含堆栈跟踪属性。
		 */
		STACK_TRACE,

		/**
		 * 包含错误消息属性。
		 */
		MESSAGE,

		/**
		 * 包含绑定错误属性。
		 */
		BINDING_ERRORS

	}

}
